/**
      <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <2011>  <André Mendes de Oliveira Paiva>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  
 */

package estrutura.cpm;

import estrutura.Aresta;
import estrutura.EstruturaDados;
import estrutura.No;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;


public class AplicacaoCPM {
   private EstruturaDados estrutura;
   private int []duracaoCaminho;
   private int []antecessor;

    public AplicacaoCPM()
    {
    }
    public AplicacaoCPM(EstruturaDados estrutura)
    {
        this.estrutura = estrutura;
    }

    /**
     * @return the estrutura
     */
    public EstruturaDados getEstrutura() {
        return estrutura;
    }

    /**
     * @param estrutura the estrutura to set
     */
    public void setEstrutura(EstruturaDados estrutura) {
        this.estrutura = estrutura;
    }
    public void gerarEstruturaDados(String arquivo)
    {
      if (this.estrutura == null)
           return;
      String linha;
        try
        {
          FileReader      fr = new FileReader(arquivo);
          BufferedReader  br = new BufferedReader(fr);
          String []dados;    /* vetor de copm os dados lidos do arquivo */
          String nomeRotulo;
          int indOrigem, indDestino, duracao;
          int qtdNo = 0;
          while ((linha = br.readLine()) != null)
          {
            dados =  linha.split(" ");
            if (dados[0].equals("N")) /* A linha refere-se a um Nó */
            {
               /* insere os nós */
               for(int i = 1; i < dados.length; i++)
               {
                  if (!(dados[i].trim()).equals("")){
                    this.estrutura.inserirNo(dados[i]);
                    qtdNo++;
                  }
               }
            }
            else if (dados[0].equals("A")) /* A linha refere-se a uma Aresta */
            {
                  /* insere as arestas */
                  try
                  {
                     indOrigem  = Integer.parseInt(dados[1].trim());
                     indDestino = Integer.parseInt(dados[2].trim());
                     nomeRotulo = dados[3].trim();
                     duracao    = Integer.parseInt(dados[4].trim());
                  }
                  catch(Exception e)
                  {
                     indOrigem  = -1;
                     indDestino = -1;
                     nomeRotulo = "";
                     duracao    = 0;
                  }
                  /* adiciona a aresta  */
                  if (indOrigem >= 0 && indOrigem < this.estrutura.getQtdeNo() && indDestino >= 0 && indDestino < this.estrutura.getQtdeNo())
                  {
                     this.estrutura.inserirAresta(indOrigem+1, indDestino+1, nomeRotulo, duracao);
                  }
            }
          }
        }
        catch (Exception e)
        {
           System.out.println("Erro ao obter os dados do arquivo: " + e.getMessage());
        }
    }

   public int definirCaminhoCritico() 
   {
      int n = this.estrutura.getQtdeNo();
      duracaoCaminho = new int[n];
      antecessor = new int[n];
      this.inicializaTempoCritico();
      int idNoOrigem = this.estrutura.obterIDNoOrigem();
      this.obterCaminhoCritico(idNoOrigem);
      int idUltimo = this.estrutura.obterIDNoDestino();
      this.imprimirCaminhoCritico(idNoOrigem, idUltimo);
      return this.duracaoCaminho[idUltimo];
   }
   public void inicializaTempoCritico()
   {
       for(int i = 0 ; i < duracaoCaminho.length; i++)
         duracaoCaminho[i] = 0;
   }
  public void obterCaminhoCritico(int pIdNoOrigem)
   {
      Aresta aresta = null;
      int duracaoAresta = 0, idNoSucessor;
      ArrayList<No> listaNoVizinhos = this.estrutura.obterNosVizinhos(pIdNoOrigem);
      while(!listaNoVizinhos.isEmpty())
      {
         idNoSucessor = listaNoVizinhos.get(listaNoVizinhos.size()-1).getId();
         listaNoVizinhos.remove(listaNoVizinhos.size()-1);
         aresta = this.estrutura.obterAresta(pIdNoOrigem, idNoSucessor);
         if (aresta != null)
         {
             duracaoAresta = duracaoCaminho[pIdNoOrigem] + aresta.getPeso();
             if(duracaoCaminho[idNoSucessor] <= duracaoAresta)
	     {
	       duracaoCaminho[idNoSucessor] = duracaoAresta;
               antecessor[idNoSucessor] = pIdNoOrigem;
             }
             obterCaminhoCritico(idNoSucessor);
         }
      }
   }
  public void imprimirCaminhoCritico(int idOrigem, int idDestino)
  {
    //int i;
    No no = this.estrutura.obterNo(idDestino);
    if (no != null)
    {
        if (idOrigem == idDestino) System.out.println (no.getValor());
        else if (this.antecessor[idDestino] == 0)
          System.out.println ("Nao existe caminho de " + idOrigem + " ate " + idDestino);
        else {
           imprimirCaminhoCritico (idOrigem, this.antecessor[idDestino]);
           System.out.println (no.getValor());
        }
    }
   }
}
